﻿using System;
using System.Collections.Generic;
using System.Reflection;
public class ParseTimeLineRet {
    public string timeLineStr = null;
    public float SkillDuration = 0.0f;
}
public class SkillManager
{
    private static SkillManager instance;
    private Dictionary<int, Dictionary<string, MethodInfo>> skillModelSet;// key:skillModelType, value:(key:functionName, value:function)
    private List<Type> allSkillConfigTypes = new List<Type>();
    private Dictionary<int, List<SkillTimePoint>> allSkillTimeLine = new Dictionary<int, List<SkillTimePoint>>();
    private SkillManager()
    {
        
    }
    
    public static SkillManager Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new SkillManager();
            }

            return instance;
        }
    }

    public void Init()
    {
        if (skillModelSet == null)
        {
            skillModelSet = new Dictionary<int, Dictionary<string, MethodInfo>>();
            ScanAllSkillModelAndConfig();
        }
    }

    private void ScanAllSkillModelAndConfig()
    {
        Assembly[] assemblys = AppDomain.CurrentDomain.GetAssemblies();
        foreach (Assembly assembly in assemblys)
        {
            Type[] allTypes = assembly.GetTypes();
            foreach (Type type in allTypes)
            {
                SkillModel skillModel = type.GetCustomAttribute<SkillModel>();
                if (skillModel != null)
                {
                    ScanOneSkillModel(type, skillModel);
                }
                
                SkillConfig skillConfig = type.GetCustomAttribute<SkillConfig>();
                if (skillConfig != null)
                {
                    ScanOneSkillConfig(type, skillConfig);
                }
            }
        }
    }

    private void ScanOneSkillConfig(Type type, SkillConfig skillConfig)
    {
        allSkillConfigTypes.Add(type);
    }

    private void ScanOneSkillModel(Type type, SkillModel skillModel)
    {
        MethodInfo[] funcs = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
        for (int i = 0; i < funcs.Length; i++)
        {
            MethodInfo methodInfo = funcs[i];
            SkillProcesser processer = methodInfo.GetCustomAttribute<SkillProcesser>();
            if (processer == null)
            {
                continue;
            }

            int key = skillModel.mainType + processer.subType;
            Dictionary<string, MethodInfo> processFuncs = null;
            if (skillModelSet.ContainsKey(key))
            {
                processFuncs = skillModelSet[key];
            }
            else
            {
                processFuncs = new Dictionary<string, MethodInfo>();
                skillModelSet.Add(key, processFuncs);
            }

            string name = processer.funcName;
            processFuncs[name] = methodInfo;
        }
    }

    public object GetSkillConfig(int skillId)
    {
        object config = null;
        for (int i = 0; i < this.allSkillConfigTypes.Count; i++)
        {
            config = ExcelDataMgr.Instance.GetConfigData(this.allSkillConfigTypes[i], skillId.ToString());
            if (config != null)
            {
                return config;
            }
        }

        return null;
    }

    public List<SkillTimePoint> ParseTimeLine(int skillId)
    {
        if (allSkillTimeLine.ContainsKey(skillId))
        {
            return allSkillTimeLine[skillId];
        }

        int mainType = skillId / 1000000;
        // int subKey = skillId % 1000000;
        int key = mainType * 1000000;
        key = key - 1; //默认值是 -1
        Dictionary<string, MethodInfo> funMap = null;
        Dictionary<string, MethodInfo> defaultFunMap = null;
        if (skillModelSet.ContainsKey(key))
        {
            defaultFunMap = this.skillModelSet[key];
        }

        if (skillModelSet.ContainsKey(skillId))
        {
            funMap = this.skillModelSet[skillId];
        }
        else
        {
            funMap = defaultFunMap;
        }

        if (funMap == null)
        {
            return null;
        }

        MethodInfo getTimeLineStr = this.GetProcessFunc("TimeLine", funMap, defaultFunMap);
        if (getTimeLineStr == null)
        {
            return null;
        }

        object[] paramDatas = new object[] { skillId };
        ParseTimeLineRet ret = (ParseTimeLineRet)getTimeLineStr.Invoke(null, paramDatas);
        if (ret == null || ret.timeLineStr == null)
        {
            return null;
        }

        List<SkillTimePoint> timeLine = new List<SkillTimePoint>();
        timeLine.Add(new SkillTimePoint(0, GetProcessFunc("Init", funMap, defaultFunMap)));
        timeLine.Add(new SkillTimePoint(0, GetProcessFunc("Begin", funMap, defaultFunMap)));
        //假设技能进行到一半的时候开始进行伤害计算
        timeLine.Add(new SkillTimePoint(ret.SkillDuration * 0.5f, GetProcessFunc("Calc", funMap, defaultFunMap)));
        timeLine.Add(new SkillTimePoint(ret.SkillDuration , GetProcessFunc("End", funMap, defaultFunMap)));

        string[] resulsts = ret.timeLineStr.Split('|');
        for (int i = 0; i < resulsts.Length; i += 2)
        {
            string funcName = resulsts[i];
            float time = float.Parse(resulsts[i + 1]);
            if (funcName.Equals("Init"))
            {
                timeLine[0].exceTime = time;
            }else if (funcName.Equals("Begin"))
            {
                timeLine[1].exceTime = time;
            }
            else if (funcName.Equals("Calc"))
            {
                timeLine[2].exceTime = time;
            }
            else if (funcName.Equals("End"))
            {
                timeLine[3].exceTime = time;
            }
            else
            {
                MethodInfo m = GetProcessFunc(funcName, funMap, defaultFunMap);
                if (m != null)
                {
                    timeLine.Add(new SkillTimePoint(time, m));
                }
            }
        }
        this.allSkillTimeLine.Add(skillId, timeLine);
        return timeLine;
    }

    private MethodInfo GetProcessFunc(string funcName, Dictionary<string, MethodInfo> funMap, Dictionary<string, MethodInfo> defaultFunMap)
    {
        if (funMap.ContainsKey(funcName))
        {
            return funMap[funcName];
        }

        if (defaultFunMap.ContainsKey(funcName))
        {
            return defaultFunMap[funcName];
        }

        return null;
    }

    public List<SkillTimeNode> GetSkillTimeLineNode(int skillId)
    {
        List<SkillTimePoint> timePoints = ParseTimeLine(skillId);
        List<SkillTimeNode> result = new List<SkillTimeNode>();
        for (int i = 0; i < timePoints.Count; i++)
        {
            SkillTimeNode node = new SkillTimeNode(timePoints[i]);
            result.Add(node);
        }

        return result;
    }
}